package plus.easydo.easypush.oauth;

import cn.hutool.core.text.CharSequenceUtil;
import cn.hutool.crypto.SecureUtil;
import cn.hutool.crypto.asymmetric.KeyType;
import cn.hutool.crypto.asymmetric.RSA;
import me.zhyd.oauth.cache.AuthStateCache;
import me.zhyd.oauth.model.AuthUser;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import plus.easydo.core.exception.HasPermissionException;
import plus.easydo.easypush.vo.UserInfoVo;
import plus.easydo.starter.redis.RedisUtils;

import java.util.concurrent.TimeUnit;

/**
 * @author laoyu
 * @version 1.0
 * @date 2022/2/23
 */
@Component
public class AuthStateRedisCache implements AuthStateCache {

    private static final String PREFIX = "easy_push_oauth:";

    private static final String AUTH_USER = "auth_user:";

    private static final String SECRET_TOKEN = "secret_token:";

    private static final String USER_INFO = "user_info:";

    private static final String PUBLIC_KEY = "publicKey";

    private static final String PRIVATE_KEY = "privateKey";

    @Autowired
    RedisUtils<Object> redisUtils;

    @Override
    public void cache(String key, String value) {
        redisUtils.set(PREFIX + key, value);
    }

    @Override
    public void cache(String key, String value, long timeout) {
        redisUtils.set(PREFIX + key, value, timeout, TimeUnit.MILLISECONDS);
    }

    @Override
    public String get(String key) {
        return (String) redisUtils.get(PREFIX + key);
    }

    @Override
    public boolean containsKey(String key) {
        return redisUtils.hasKey(PREFIX + key);
    }

    public void cacheAuthUser(AuthUser authUser, String platform, Long id) {
        redisUtils.set(PREFIX + AUTH_USER + platform + ":" + id, authUser);
    }

    public AuthUser getAuthUser(String platform, Long id) {
        return (AuthUser) redisUtils.get(PREFIX + AUTH_USER + platform + ":" + id);
    }

    public Boolean removeAuthUser(String platform, Long id) {
        return redisUtils.delete(PREFIX + AUTH_USER + platform + ":" + id);
    }

    public Boolean removeAuthUser(String token) {
        UserInfoVo userInfoVo = getUserCacheByToken(token);
        return redisUtils.delete(PREFIX + AUTH_USER + userInfoVo.getPlatform() + ":" + userInfoVo.getId());
    }

    public void cacheUser(UserInfoVo userInfoVo) {
        redisUtils.set(PREFIX + USER_INFO + userInfoVo.getSecret(), userInfoVo, 30, TimeUnit.MINUTES);
    }

    public UserInfoVo getUserCacheByToken(String token) {
        RSA ras = SecureUtil.rsa(getPrivateKey(), null);
        String secret = ras.decryptStr(token,KeyType.PrivateKey);
        return (UserInfoVo) redisUtils.get(PREFIX + USER_INFO + secret);
    }
    public UserInfoVo getUserCacheBySecret(String secret) {
        return (UserInfoVo) redisUtils.get(PREFIX + USER_INFO + secret);
    }

    public Boolean removeUserCache(String secret) {
        return redisUtils.delete(PREFIX + USER_INFO + secret);
    }

    public String cacheToken(UserInfoVo userInfoVo) {
        String secret = userInfoVo.getSecret();
        RSA ras = SecureUtil.rsa(null, getPublicKey());
        String token = ras.encryptBase64(secret, KeyType.PublicKey);
        redisUtils.set(PREFIX + SECRET_TOKEN+ secret, token, 30, TimeUnit.MINUTES);
        return token;
    }

    public String getToken(String secret) {
        return (String) redisUtils.get(PREFIX + SECRET_TOKEN+ secret);
    }

    public boolean checkToken(String token) {
        if (CharSequenceUtil.isBlank(token)) {
            throw new HasPermissionException("token不能为空");
        }
        RSA ras = SecureUtil.rsa(getPrivateKey(), getPublicKey());
        String secret = ras.decryptStr(token,KeyType.PrivateKey);
       if(redisUtils.hasKey(PREFIX + SECRET_TOKEN + secret)){
        return true;
       }
       throw new HasPermissionException("token校验失败");
    }

    public void removeToken(String secret) {
        redisUtils.delete(PREFIX + SECRET_TOKEN+ secret);
    }

    public String getPublicKey() {
        String publicKey = (String) redisUtils.get(PREFIX + PUBLIC_KEY);
        if (CharSequenceUtil.isBlank(publicKey)) {
            initKey();
        }
        return (String) redisUtils.get(PREFIX + PUBLIC_KEY);
    }

    public String getPrivateKey() {
        String privateKey = (String) redisUtils.get(PREFIX + PRIVATE_KEY);
        if (CharSequenceUtil.isBlank(privateKey)) {
            initKey();
        }
        return (String) redisUtils.get(PREFIX + PRIVATE_KEY);
    }

    private void initKey() {
        RSA rsa = new RSA();
        //获得私钥
        String privateKey = rsa.getPrivateKeyBase64();
        //获得公钥
        String publicKey = rsa.getPublicKeyBase64();
        redisUtils.set(PREFIX + PRIVATE_KEY, privateKey);
        redisUtils.set(PREFIX + PUBLIC_KEY, publicKey);
    }

    public void logout(String token) {
        if(checkToken(token)){
            RSA ras = SecureUtil.rsa(getPrivateKey(), getPublicKey());
            String secret = ras.decryptStr(token,KeyType.PrivateKey);
            removeAuthUser(token);
            removeUserCache(secret);
            removeToken(secret);
        }
    }
}
